Let the style stuff be handled by an external (gperf) perfect hash generator.
authorrobertl <robertl>
Sun, 26 Aug 2007 20:40:40 +0000 (20:40 +0000)
committerrobertl <robertl>
Sun, 26 Aug 2007 20:40:40 +0000 (20:40 +0000)
Makefile.in
csv_util.c
xcsv_tokens.in [new file with mode: 0644]

index b8891cdfb9de8969987e4037541a24936fd310ba..b15191c1e7aa7eb819ae17fbf4ecdb9f71816666 100644 (file)
@@ -109,6 +109,9 @@ gpsbabel-debug: $(OBJS)
 Makefile gbversion.h: Makefile.in config.status xmldoc/makedoc.in gbversion.h.in
        CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status 
 
+xcsv_tokens.gperf: xcsv_tokens.in
+       gperf -t --output-file=$@ $?
+
 config.status: configure 
        $(SHELL) config.status --recheck
 
@@ -376,7 +379,7 @@ csv_util.o: csv_util.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \
   jeeps/gpsdevice.h jeeps/gpssend.h jeeps/gpsread.h jeeps/gpsutil.h \
   jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h jeeps/gpsfmt.h \
   jeeps/gpsmath.h jeeps/gpsmem.h jeeps/gpsrqst.h jeeps/gpsinput.h \
-  jeeps/gpsproj.h xmlgeneric.h
+  jeeps/gpsproj.h xmlgeneric.h xcsv_tokens.gperf
 delgpl.o: delgpl.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \
   zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h
 discard.o: discard.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \
index 5fb1bffc6ef64fdc88cd316792099ebb2da927d4..a612a60c97366b03a76ddd4cc31620faeca76489 100644 (file)
@@ -2,7 +2,7 @@
     Utilities for parsing Character Separated Value files (CSV)
 
     Copyright (C) 2002 Alex Mottram (geo_alexm at cox-internet.com)
-    Copyright (C) 2002-2005 Robert Lipe
+    Copyright (C) 2002-2007 Robert Lipe
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 
 #define GPS_DATUM_WGS84                118
 
+
+/*
+ * Internal numeric value to associate with each keyword in a style file.
+ * To add new keywords, just add an entry here, handle it in the switch
+ * statements below, add it to xcsv_tokens.in, and rebuild on a system
+ * that has GNU gperf on it.
+ */
+typedef enum {
+       XT_unused = 0,
+       XT_ALT_FEET,
+       XT_ALT_METERS,
+       XT_ANYNAME,
+       XT_CADENCE,
+       XT_CONSTANT,
+       XT_DESCRIPTION,
+       XT_EXCEL_TIME,
+       XT_GEOCACHE_CONTAINER,
+       XT_GEOCACHE_DIFF,
+       XT_GEOCACHE_HINT,
+       XT_GEOCACHE_LAST_FOUND,
+       XT_GEOCACHE_PLACER,
+       XT_GEOCACHE_TERR,
+       XT_GEOCACHE_TYPE,
+       XT_GMT_TIME,
+       XT_GPS_FIX,
+       XT_GPS_HDOP,
+       XT_GPS_PDOP,
+       XT_GPS_SAT,
+       XT_GPS_VDOP,
+       XT_HEART_RATE,
+       XT_HMSG_TIME,
+       XT_HMSL_TIME,
+       XT_ICON_DESCR,
+       XT_IGNORE,
+       XT_INDEX,
+       XT_ISO_TIME,
+       XT_ISO_TIME_MS,
+       XT_LATLON_HUMAN_READABLE,
+       XT_LAT_DECIMAL,
+       XT_LAT_DECIMALDIR,
+       XT_LAT_DIR,
+       XT_LAT_DIRDECIMAL,
+       XT_LAT_HUMAN_READABLE,
+       XT_LAT_INT32DEG,
+       XT_LAT_NMEA,
+       XT_LOCAL_TIME,
+       XT_LON_DECIMAL,
+       XT_LON_DECIMALDIR,
+       XT_LON_DIR,
+       XT_LON_DIRDECIMAL,
+       XT_LON_HUMAN_READABLE,
+       XT_LON_INT32DEG,
+       XT_LON_NMEA,
+       XT_MAP_EN_BNG,
+       XT_NOTES,
+       XT_PATH_COURSE,
+       XT_PATH_DISTANCE_KM,
+       XT_PATH_DISTANCE_MILES,
+       XT_PATH_SPEED,
+       XT_PATH_SPEED_KNOTS,
+       XT_PATH_SPEED_KPH,
+       XT_PATH_SPEED_MPH,
+       XT_ROUTE_NAME,
+       XT_SHORTNAME,
+       XT_TIMET_TIME,
+       XT_TRACK_NAME,
+       XT_URL,
+       XT_URL_LINK_TEXT,
+       XT_YYYYMMDD_TIME
+} xcsv_token;
+
+#include "xcsv_tokens.gperf"
+
 /****************************************************************************/
 /* obligatory global struct                                                 */
 /****************************************************************************/
@@ -601,8 +674,10 @@ void
 xcsv_ifield_add(char *key, char *val, char *pfc)
 {
     field_map_t *fmp = xcalloc(sizeof(*fmp), 1);
+    struct xt_mapping *xm = in_word_set(key, strlen(key));
     
     fmp->key = key;
+    fmp->hashed_key = xm ? xm->xt_token : -1;
     fmp->val = val;
     fmp->printfc = pfc;
     
@@ -618,8 +693,10 @@ void
 xcsv_ofield_add(char *key, char *val, char *pfc, int options)
 {
     field_map_t *fmp = xcalloc(sizeof(*fmp), 1);
+    struct xt_mapping *xm = in_word_set(key, strlen(key));
     
     fmp->key = key;
+    fmp->hashed_key = xm ? xm->xt_token : -1;
     fmp->val = val;
     fmp->printfc = pfc;
     fmp->options = options;
@@ -798,203 +875,201 @@ static void
 xcsv_parse_val(const char *s, waypoint *wpt, const field_map_t *fmp)
 {
     char *enclosure = "";
+
     if (0 == strcmp(fmp->printfc, "\"%s\"")) {
        enclosure = "\"";
     }
-    if (strcmp(fmp->key, "IGNORE") == 0) {
-       /* IGNORE -- Categorically ignore this... */
-    } else
-    if (strcmp(fmp->key, "CONSTANT") == 0) {
-       /* CONSTANT -- Ignore on Input... */
-    } else
-    if (strcmp(fmp->key, "ANYNAME") == 0) {
-       /* ANYNAME -- Ignore -- this is output magic. */
-    } else
-    if (strcmp(fmp->key, "INDEX") == 0) {
-       /* IGNORE -- Calculated Sequence # For Ouput*/
-    } else
-    if (strcmp(fmp->key, "SHORTNAME") == 0) {
-       wpt->shortname = csv_stringtrim(s, enclosure, 0);
-    } else
-    if (strcmp(fmp->key, "DESCRIPTION") == 0) {
-       wpt->description = csv_stringtrim(s, enclosure, 0);
-    } else
-    if (strcmp(fmp->key, "NOTES") == 0) {
-       wpt->notes = csv_stringtrim(s, "", 0);
-    } else
-    if (strcmp(fmp->key, "URL") == 0) {
-       wpt->url = csv_stringtrim(s, "", 0);
-    } else
-    if (strcmp(fmp->key, "URL_LINK_TEXT") == 0) {
-       wpt->url_link_text = csv_stringtrim(s, "", 0);
-    } else
-    if (strcmp(fmp->key, "ICON_DESCR") == 0) {
-       wpt->icon_descr = csv_stringtrim(s, "", 0);
-       wpt->wpt_flags.icon_descr_is_dynamic = 1;
-    } else
+    switch(fmp->hashed_key) {
+    case XT_IGNORE:
+       /* IGNORE -- Categorically ignore this... */
+       break;
+    case XT_CONSTANT:
+       /* CONSTANT -- Ignore on Input... */
+       break;
+    case XT_ANYNAME:
+       /* ANYNAME -- Ignore -- this is output magic. */
+       break;
+    case XT_INDEX:
+       /* IGNORE -- Calculated Sequence # For Ouput*/
+       break;
+    case XT_SHORTNAME:
+       wpt->shortname = csv_stringtrim(s, enclosure, 0);
+       break;
+    case XT_DESCRIPTION:
+       wpt->description = csv_stringtrim(s, enclosure, 0);
+       break;
+    case XT_NOTES:
+       wpt->notes = csv_stringtrim(s, "", 0);
+       break;
+    case XT_URL:
+       wpt->url = csv_stringtrim(s, "", 0);
+       break;
+    case XT_URL_LINK_TEXT:
+       wpt->url_link_text = csv_stringtrim(s, "", 0);
+       break;
+    case XT_ICON_DESCR:
+       wpt->icon_descr = csv_stringtrim(s, "", 0);
+       wpt->wpt_flags.icon_descr_is_dynamic = 1;
+       break;
 
     /* LATITUDE CONVERSIONS**************************************************/
-    if (strcmp(fmp->key, "LAT_DECIMAL") == 0) {
+    case XT_LAT_DECIMAL:
        /* latitude as a pure decimal value */
-       wpt->latitude = atof(s);
-    } else
-    if ((strcmp(fmp->key, "LAT_DECIMALDIR") == 0) ||
-        (strcmp(fmp->key, "LAT_DIRDECIMAL") == 0)) {
-       /* latitude as a decimal with N/S in it. */
-       wpt->latitude = decdir_to_dec(s);
-    } else
-    if (strcmp(fmp->key, "LAT_INT32DEG") == 0) {
-       /* latitude as a 32 bit integer offset */
-       wpt->latitude = intdeg_to_dec((int) atof(s));
-    } else
-    if ( strcmp(fmp->key, "LAT_HUMAN_READABLE") == 0) {
-       human_to_dec( s, &wpt->latitude, &wpt->longitude, 1 );
-    } else
-    if ( strcmp(fmp->key, "LAT_NMEA") == 0) {
+       wpt->latitude = atof(s);
+       break;
+    case XT_LAT_DECIMALDIR:
+    case XT_LAT_DIRDECIMAL:
+       /* latitude as a decimal with N/S in it. */
+       wpt->latitude = decdir_to_dec(s);
+       break;
+    case XT_LAT_INT32DEG:
+       /* latitude as a 32 bit integer offset */
+       wpt->latitude = intdeg_to_dec((int) atof(s));
+       break;
+    case XT_LAT_HUMAN_READABLE:
+       human_to_dec( s, &wpt->latitude, &wpt->longitude, 1 );
+       break;
+    case XT_LAT_NMEA:
        wpt->latitude = ddmm2degrees(atof(s));
-    } else
-    if ( strncmp(fmp->key, "LAT_10E", 7) == 0) {
-       wpt->latitude = atof(s) / pow((double)10, atof(fmp->key+7));
-    } else
+       break;
+    // XT_LAT_10E is handled outside the switch.
     /* LONGITUDE CONVERSIONS ***********************************************/
-    if (strcmp(fmp->key, "LON_DECIMAL") == 0) {
+    case XT_LON_DECIMAL:
        /* longitude as a pure decimal value */
-       wpt->longitude = atof(s);
-    } else
-    if ((strcmp(fmp->key, "LON_DECIMALDIR") == 0) ||
-        (strcmp(fmp->key, "LON_DIRDECIMAL") == 0)) {
+       wpt->longitude = atof(s);
+       break;
+    case XT_LON_DECIMALDIR:
+    case XT_LON_DIRDECIMAL:
        /* longitude as a decimal with N/S in it. */
-       wpt->longitude = decdir_to_dec(s);
-    } else
-    if (strcmp(fmp->key, "LON_INT32DEG") == 0) {
+       wpt->longitude = decdir_to_dec(s);
+       break;
+    case XT_LON_INT32DEG:
        /* longitude as a 32 bit integer offset  */
-       wpt->longitude = intdeg_to_dec((int) atof(s));
-    } else
-    if ( strcmp(fmp->key, "LON_HUMAN_READABLE") == 0) {
-       human_to_dec( s, &wpt->latitude, &wpt->longitude, 2 );
-    } else
-    if ( strcmp(fmp->key, "LON_NMEA") == 0) {
+       wpt->longitude = intdeg_to_dec((int) atof(s));
+       break;
+    case XT_LON_HUMAN_READABLE:
+       human_to_dec( s, &wpt->latitude, &wpt->longitude, 2 );
+       break;
+    case XT_LON_NMEA:
        wpt->longitude = ddmm2degrees(atof(s));
-    } else
-    if ( strncmp(fmp->key, "LON_10E", 7) == 0) {
-       wpt->longitude = atof(s) / pow((double)10, atof(fmp->key+7));
-    } else
+       break;
+    // case XT_LON_10E is handled outside the switch.
     /* LAT AND LON CONVERSIONS ********************************************/
-    if ( strcmp(fmp->key, "LATLON_HUMAN_READABLE") == 0) {
-       human_to_dec( s, &wpt->latitude, &wpt->longitude, 0 );
-    } else
+    case XT_LATLON_HUMAN_READABLE:
+       human_to_dec( s, &wpt->latitude, &wpt->longitude, 0 );
+       break;
     /* DIRECTIONS **********************************************************/
-    if (strcmp(fmp->key, "LAT_DIR") == 0) {
-       /* latitude N/S.  Ignore on input for now */
-    } else
-    if (strcmp(fmp->key, "LON_DIR") == 0) {
-       /* longitude E/W. Ingore on input for now */
-    } else
+    case XT_LAT_DIR:
+       /* latitude N/S.  Ignore on input for now */
+       break;
+    case XT_LON_DIR:
+       /* longitude E/W. Ingore on input for now */
+       break;
     /* SPECIAL COORDINATES/GRID */
-    if (strcmp(fmp->key, "MAP_EN_BNG") == 0) {
-       parse_coordinates(s, DATUM_OSGB36, grid_bng,
-          &wpt->latitude, &wpt->longitude, MYNAME);
-    } else
+    case XT_MAP_EN_BNG:
+       parse_coordinates(s, DATUM_OSGB36, grid_bng,
+               &wpt->latitude, &wpt->longitude, MYNAME);
+       break;
     /* ALTITUDE CONVERSIONS ************************************************/
-    if (strcmp(fmp->key, "ALT_FEET") == 0) {
-       /* altitude in feet as a decimal value */
-       wpt->altitude = FEET_TO_METERS(atof(s));
-       if (wpt->altitude < unknown_alt + 1)
-          wpt->altitude = unknown_alt;
-    } else
-    if (strcmp(fmp->key, "ALT_METERS") == 0) {
-       /* altitude in meters as a decimal value */
-       wpt->altitude = atof(s);
-       if (wpt->altitude < unknown_alt + 1)
-          wpt->altitude = unknown_alt;
-    } else
+    case XT_ALT_FEET:
+       /* altitude in feet as a decimal value */
+       wpt->altitude = FEET_TO_METERS(atof(s));
+       if (wpt->altitude < unknown_alt + 1)
+               wpt->altitude = unknown_alt;
+       break;
+    case XT_ALT_METERS:
+       /* altitude in meters as a decimal value */
+       wpt->altitude = atof(s);
+       if (wpt->altitude < unknown_alt + 1)
+               wpt->altitude = unknown_alt;
+       break;
     
     /* PATH CONVERSIONS ************************************************/
-    if (strcmp(fmp->key, "PATH_SPEED") == 0) {
+    case XT_PATH_SPEED:
        WAYPT_SET(wpt, speed, atof(s));
-    } else
-    if (strcmp(fmp->key, "PATH_SPEED_KPH") == 0) {
+       break;
+    case XT_PATH_SPEED_KPH:
        WAYPT_SET(wpt, speed, KPH_TO_MPS(atof(s)));
-    } else
-    if (strcmp(fmp->key, "PATH_SPEED_MPH") == 0) {
+       break;
+    case XT_PATH_SPEED_MPH:
        WAYPT_SET(wpt, speed, MPH_TO_MPS(atof(s)));
-    } else
-    if (strcmp(fmp->key, "PATH_SPEED_KNOTS") == 0) {
+       break;
+    case XT_PATH_SPEED_KNOTS:
        WAYPT_SET(wpt, speed, KNOTS_TO_MPS(atof(s)));
-    } else
-    if (strcmp(fmp->key, "PATH_COURSE") == 0) {
+       break;
+    case XT_PATH_COURSE:
        WAYPT_SET(wpt, course, atof(s));
-    } else
+       break;
 
     /* TIME CONVERSIONS ***************************************************/
-    if (strcmp(fmp->key, "EXCEL_TIME") == 0) {
+    case XT_EXCEL_TIME:
        /* Time as Excel Time  */
-       wpt->creation_time = EXCEL_TO_TIMET(atof(s));
-    } else
-    if (strcmp(fmp->key, "TIMET_TIME") == 0) {
+       wpt->creation_time = EXCEL_TO_TIMET(atof(s));
+       break;
+    case XT_TIMET_TIME:
        /* Time as time_t */
-       wpt->creation_time = atol(s);
-     } else
-    if (strcmp(fmp->key, "YYYYMMDD_TIME") == 0) {
+       wpt->creation_time = atol(s);
+       break;
+    case XT_YYYYMMDD_TIME:
        wpt->creation_time = yyyymmdd_to_time(s);
-    } else
-    if (strcmp(fmp->key, "GMT_TIME") == 0) {
+       break;
+    case XT_GMT_TIME:
        wpt->creation_time = sscanftime(s, fmp->printfc, 1);
-    } else
-    if (strcmp(fmp->key, "LOCAL_TIME") == 0) {
+       break;
+    case XT_LOCAL_TIME:
        wpt->creation_time = sscanftime(s, fmp->printfc, 0);
-    } else
+       break;
     /* Useful when time and date are in separate fields 
        GMT / Local offset is handled by the two cases above */
-    if ((strcmp(fmp->key, "HMSG_TIME") == 0)||
-       (strcmp(fmp->key, "HMSL_TIME") == 0) ) {
+    case XT_HMSG_TIME:
+    case XT_HMSL_TIME:
        wpt->creation_time += addhms(s, fmp->printfc);
-    } else
-    if ((strcmp(fmp->key, "ISO_TIME") == 0) || 
-        (strcmp(fmp->key, "ISO_TIME_MS") == 0)) {
+       break;
+    case XT_ISO_TIME: 
+    case XT_ISO_TIME_MS: 
        wpt->creation_time = xml_parse_time(s, &wpt->microseconds);
-    } else
-       if (strcmp(fmp->key, "GEOCACHE_LAST_FOUND") == 0) {
+       break;
+       case XT_GEOCACHE_LAST_FOUND:
        wpt->gc_data.last_found = yyyymmdd_to_time(s);
-    } else
+       break;
 
     /* GEOCACHING STUFF ***************************************************/
-    if (strcmp(fmp->key, "GEOCACHE_DIFF") == 0) {
+    case XT_GEOCACHE_DIFF:
        /* Geocache Difficulty as an int */
-       wpt->gc_data.diff = atof(s) * 10; 
-    } else
-    if (strcmp(fmp->key, "GEOCACHE_TERR") == 0) {
+       wpt->gc_data.diff = atof(s) * 10; 
+       break;
+    case XT_GEOCACHE_TERR:
        /* Geocache Terrain as an int */
-       wpt->gc_data.terr = atof(s) * 10;
-    } else
-    if (strcmp(fmp->key, "GEOCACHE_TYPE") == 0) {
+       wpt->gc_data.terr = atof(s) * 10;
+       break;
+    case XT_GEOCACHE_TYPE:
        /* Geocache Type */
-       wpt->gc_data.type = gs_mktype(s);
-    } else
-    if (strcmp(fmp->key, "GEOCACHE_CONTAINER") == 0) {
-       wpt->gc_data.container = gs_mkcont(s);
-    } else
-    if (strcmp(fmp->key, "GEOCACHE_HINT") == 0) {
-       wpt->gc_data.hint = csv_stringtrim(s, "", 0);
-    } else
-    if (strcmp(fmp->key, "GEOCACHE_PLACER") == 0) {
-       wpt->gc_data.placer = csv_stringtrim(s, "", 0);
-    } else
+       wpt->gc_data.type = gs_mktype(s);
+       break;
+    case XT_GEOCACHE_CONTAINER:
+       wpt->gc_data.container = gs_mkcont(s);
+       break;
+    case XT_GEOCACHE_HINT:
+       wpt->gc_data.hint = csv_stringtrim(s, "", 0);
+       break;
+    case XT_GEOCACHE_PLACER:
+       wpt->gc_data.placer = csv_stringtrim(s, "", 0);
+       break;
        
     /* GPS STUFF *******************************************************/
-    if (strcmp(fmp->key, "GPS_HDOP") == 0) {
-        wpt->hdop = atof(s);
-    } else
-    if (strcmp(fmp->key, "GPS_VDOP") == 0) {
+    case XT_GPS_HDOP:
+       wpt->hdop = atof(s);
+       break;
+    case XT_GPS_VDOP:
        wpt->vdop = atof(s);
-    } else
-    if (strcmp(fmp->key, "GPS_PDOP") == 0) {
+       break;
+    case XT_GPS_PDOP:
         wpt->pdop = atof(s);
-    } else
-    if (strcmp(fmp->key, "GPS_SAT") == 0) {
+       break;
+    case XT_GPS_SAT:
        wpt->sat = atoi(s);
-    } else
-    if (strcmp(fmp->key, "GPS_FIX") == 0) {
+       break;
+    case XT_GPS_FIX:
        wpt->fix = atoi(s)-1;
        if ( wpt->fix < fix_2d) {
        if (!case_ignore_strcmp(s, "none"))
@@ -1006,29 +1081,42 @@ xcsv_parse_val(const char *s, waypoint *wpt, const field_map_t *fmp)
        else
                wpt->fix = fix_unknown;
        }
-    } else
+       break;
     /* Tracks and routes *********************************************/
-    if ( strcmp ( fmp->key, "ROUTE_NAME") == 0) {
+    case XT_ROUTE_NAME:
        if (csv_route) csv_route->rte_name = csv_stringtrim(s, enclosure, 0);
-    } else
-    if ( strcmp ( fmp->key, "TRACK_NAME") == 0) {
+       break;
+    case XT_TRACK_NAME:
        if (csv_track) csv_track->rte_name = csv_stringtrim(s, enclosure, 0);
-    } else
+       break;
        
     /* OTHER STUFF ***************************************************/
-    if ( strcmp( fmp->key, "PATH_DISTANCE_MILES") == 0) {
-       /* Ignored on input */
-    } else
-    if ( strcmp( fmp->key, "HEART_RATE") == 0) {
-      wpt->heartrate = atoi(s); 
-    } else
-    if ( strcmp( fmp->key, "CADENCE") == 0) {
-      wpt->cadence = atoi(s); 
-    } else
-    if ( strcmp( fmp->key, "PATH_DISTANCE_KM") == 0 ) {
-       /* Ignored on input */
-    } else {
-       warning( MYNAME ": Unknown style directive: %s\n", fmp->key);
+    case XT_PATH_DISTANCE_MILES:
+       /* Ignored on input */
+       break;
+    case XT_HEART_RATE:
+       wpt->heartrate = atoi(s); 
+       break;
+    case XT_CADENCE:
+       wpt->cadence = atoi(s); 
+       break;
+    case XT_PATH_DISTANCE_KM:
+       /* Ignored on input */
+       break;
+    case -1:
+       if (strncmp(fmp->key, "LON_10E", 7) == 0) {
+               wpt->longitude = atof(s) / pow((double)10, atof(fmp->key+7));
+       } else 
+       if (strncmp(fmp->key, "LAT_10E", 7) == 0) {
+               wpt->latitude = atof(s) / pow((double)10, atof(fmp->key+7));
+       } else {
+               warning( MYNAME ": Unknown style directive: %s\n", fmp->key);
+       }
+       break;
+   
+    default:  
+       fatal("This can't happen\n");
+       break;
     }
 }
 
@@ -1261,26 +1349,28 @@ xcsv_waypt_pr(const waypoint *wpt)
 
         i++;
 #define writebuff(b, fmt, data) snprintf(b, sizeof(b), fmt, data)
-        if (strcmp(fmp->key, "IGNORE") == 0) {
+    switch(fmp->hashed_key) {
+        case XT_IGNORE:
             /* IGNORE -- Write the char printf conversion */
             writebuff(buff, fmp->printfc, "");
-        } else
-        if (strcmp(fmp->key, "INDEX") == 0) {
+            break;
+        case XT_INDEX:
             writebuff(buff, fmp->printfc, waypt_out_count + atoi(fmp->val));
-        } else
-        if (strcmp(fmp->key, "CONSTANT") == 0) {
+            break;
+        case XT_CONSTANT: {
            const char *cp = xcsv_get_char_from_constant_table(fmp->val);
            if (cp) {
                 writebuff(buff, fmp->printfc, cp);
-           } else {
+               } else {
                writebuff(buff, fmp->printfc, fmp->val);
            }
-        } else
-        if (strcmp(fmp->key, "SHORTNAME") == 0) {
+           }
+            break;
+        case XT_SHORTNAME:
             writebuff(buff, fmp->printfc, 
                 (shortname && *shortname) ? shortname : fmp->val);
-        } else
-        if (strcmp(fmp->key, "ANYNAME") == 0) {
+            break;
+        case XT_ANYNAME:
             if (wpt->shortname) {
                 anyname = xstrdup(wpt->shortname);
             } else
@@ -1299,16 +1389,16 @@ xcsv_waypt_pr(const waypoint *wpt)
             writebuff(buff, fmp->printfc, anyname);
             
             xfree(anyname);
-        } else
-        if (strcmp(fmp->key, "DESCRIPTION") == 0) {
+            break;
+        case XT_DESCRIPTION:
             writebuff(buff, fmp->printfc, 
                 (description && *description) ? description : fmp->val);
-        } else
-        if (strcmp(fmp->key, "NOTES") == 0) {
+            break;
+        case XT_NOTES:
            writebuff(buff, fmp->printfc, 
                (wpt->notes && *wpt->notes) ? wpt->notes : fmp->val);
-        } else
-        if (strcmp(fmp->key, "URL") == 0) {
+            break;
+        case XT_URL: {
            int off = 0;
            if (xcsv_urlbase) {
                strcpy(buff, xcsv_urlbase);
@@ -1318,243 +1408,239 @@ xcsv_waypt_pr(const waypoint *wpt)
                snprintf(buff + off, sizeof(buff) - off, fmp->printfc, wpt->url);
            else
                strcpy(buff, (fmp->val && *fmp->val) ? fmp->val : "\"\"");
-        } else
-        if (strcmp(fmp->key, "URL_LINK_TEXT") == 0) {
+           }
+            break;
+        case XT_URL_LINK_TEXT:
             snprintf(buff, sizeof(buff), fmp->printfc, 
                 (wpt->url_link_text && *wpt->url_link_text) ? wpt->url_link_text : fmp->val);
-        } else
-        if (strcmp(fmp->key, "ICON_DESCR") == 0) {
+            break;
+        case XT_ICON_DESCR:
             writebuff(buff, fmp->printfc, 
                 (wpt->icon_descr && *wpt->icon_descr) ? 
                 wpt->icon_descr : fmp->val);
-        } else
+            break;
 
         /* LATITUDE CONVERSION***********************************************/
-        if (strcmp(fmp->key, "LAT_DECIMAL") == 0) {
+        case XT_LAT_DECIMAL:
             /* latitude as a pure decimal value */
             writebuff(buff, fmp->printfc, lat);
-        } else
-        if (strcmp(fmp->key, "LAT_DECIMALDIR") == 0) {
+            break;
+        case XT_LAT_DECIMALDIR:
             /* latitude as a decimal value with N/S after it */
             snprintf(buff, sizeof(buff), fmp->printfc, fabs(lat), 
               LAT_DIR(lat));
-        } else
-        if (strcmp(fmp->key, "LAT_DIRDECIMAL") == 0) {
+            break;
+        case XT_LAT_DIRDECIMAL:
             /* latitude as a decimal value with N/S before it */
             snprintf(buff, sizeof(buff), fmp->printfc, 
               LAT_DIR(lat),
               fabs(lat));
-        } else
-        if (strcmp(fmp->key, "LAT_INT32DEG") == 0) {
+            break;
+        case XT_LAT_INT32DEG:
             /* latitude as an integer offset from 0 degrees */
             writebuff(buff, fmp->printfc,
               dec_to_intdeg(lat));
-        } else
-       if (strcmp(fmp->key, "LAT_HUMAN_READABLE") == 0) {
+            break;
+       case XT_LAT_HUMAN_READABLE:
            dec_to_human( buff, fmp->printfc, "SN", lat );
-       } else
-       if (strcmp(fmp->key, "LAT_NMEA") == 0) {
+           break;
+       case XT_LAT_NMEA:
            writebuff(buff, fmp->printfc, degrees2ddmm(lat));
-       } else
-       if (strncmp(fmp->key, "LAT_10E", 7) == 0) {
-           writebuff(buff, fmp->printfc, lat * pow((double)10, atof(fmp->key+7)));
-       } else
-
+           break;
+       // case XT_LAT_10E is handled outside the switch.
         /* LONGITUDE CONVERSIONS*********************************************/
-        if (strcmp(fmp->key, "LON_DECIMAL") == 0) {
+        case XT_LON_DECIMAL:
             /* longitude as a pure decimal value */
             writebuff(buff, fmp->printfc, lon);
-        } else
-        if (strcmp(fmp->key, "LON_DECIMALDIR") == 0) {
+            break;
+        case XT_LON_DECIMALDIR:
             /* latitude as a decimal value with N/S after it */
             snprintf(buff, sizeof(buff),  fmp->printfc,
               fabs(lon), 
               LON_DIR(lon));
-        } else
-        if (strcmp(fmp->key, "LON_DIRDECIMAL") == 0) {
+            break;
+        case XT_LON_DIRDECIMAL:
             /* latitude as a decimal value with N/S before it */
             snprintf(buff, sizeof(buff), fmp->printfc,
               LON_DIR(lon),
               fabs(lon));
-        } else
-        if (strcmp(fmp->key, "LON_INT32DEG") == 0) {
+            break;
+        case XT_LON_INT32DEG:
             /* longitudee as an integer offset from 0 degrees */
             writebuff(buff, fmp->printfc,
               dec_to_intdeg(lon));
-        } else
-       if (strcmp(fmp->key, "LON_HUMAN_READABLE") == 0) {
+            break;
+       case XT_LON_HUMAN_READABLE:
            dec_to_human( buff, fmp->printfc, "WE", lon );
-       } else
-       if (strcmp(fmp->key, "LATLON_HUMAN_READABLE") == 0) {
+           break;
+       case XT_LATLON_HUMAN_READABLE:
            dec_to_human( buff, fmp->printfc, "SN", lat );
            if ( !isspace(buff[strlen(buff)])) strcat( buff, " " );
            dec_to_human( buff+strlen(buff), fmp->printfc, "WE", 
                            lon );
-       } else
-       if (strcmp(fmp->key, "LON_NMEA") == 0) {
+           break;
+       case XT_LON_NMEA:
                writebuff(buff, fmp->printfc, degrees2ddmm(lon));
-       } else
-       if (strncmp(fmp->key, "LON_10E", 7) == 0) {
-           writebuff(buff, fmp->printfc, lon * pow((double)10, atof(fmp->key+7)));
-       } else
-
+           break;
+       // case XT_LON_10E is handled outside the switch.
         /* DIRECTIONS *******************************************************/
-        if (strcmp(fmp->key, "LAT_DIR") == 0) {
+        case XT_LAT_DIR:
             /* latitude N/S as a char */
             writebuff(buff, fmp->printfc,
             LAT_DIR(lat));
-        } else
-        if (strcmp(fmp->key, "LON_DIR") == 0) {
+            break;
+        case XT_LON_DIR:
             /* longitude E/W as a char */
             writebuff(buff, fmp->printfc,
               LON_DIR(lon));
-        } else
+            break;
        
        /* SPECIAL COORDINATES */
-        if (strcmp(fmp->key, "MAP_EN_BNG") == 0) {
+        case XT_MAP_EN_BNG: {
                char map[3];
                double north, east;
                if (! GPS_Math_WGS84_To_UKOSMap_M(wpt->latitude, wpt->longitude, &east, &north, map))
                        fatal(MYNAME ": Position (%.5f/%.5f) outside of BNG.\n",
                                wpt->latitude, wpt->longitude);
                snprintf(buff, sizeof(buff), fmp->printfc, map, (int)(east + 0.5), (int)(north + 0.5));
-       } else
+               }
+           break;
 
         /* ALTITUDE CONVERSIONS**********************************************/
-        if (strcmp(fmp->key, "ALT_FEET") == 0) {
+        case XT_ALT_FEET:
             /* altitude in feet as a decimal value */
             writebuff(buff, fmp->printfc,
               METERS_TO_FEET(wpt->altitude));
-        } else
-        if (strcmp(fmp->key, "ALT_METERS") == 0) {
+            break;
+        case XT_ALT_METERS:
             /* altitude in meters as a decimal value */
             writebuff(buff, fmp->printfc,
               wpt->altitude);
-        } else
+            break;
                
         /* DISTANCE CONVERSIONS**********************************************/
-       if (strcmp(fmp->key, "PATH_DISTANCE_MILES") == 0) {
+       case XT_PATH_DISTANCE_MILES:
             /* path (route/track) distance in miles */
             writebuff( buff, fmp->printfc, pathdist );
-       } else
-       if (strcmp(fmp->key, "PATH_DISTANCE_KM") == 0) {
+           break;
+       case XT_PATH_DISTANCE_KM:
             /* path (route/track) distance in  */
             writebuff( buff, fmp->printfc, pathdist * 5280*12*2.54/100/1000 );
-       } else
-       if (strcmp(fmp->key, "PATH_SPEED") == 0) {
+           break;
+       case XT_PATH_SPEED:
             writebuff( buff, fmp->printfc, wpt->speed );
-       } else
-       if (strcmp(fmp->key, "PATH_SPEED_KPH") == 0) {
+           break;
+       case XT_PATH_SPEED_KPH:
             writebuff( buff, fmp->printfc, MPS_TO_KPH(wpt->speed));
-       } else
-       if (strcmp(fmp->key, "PATH_SPEED_MPH") == 0) {
+           break;
+       case XT_PATH_SPEED_MPH:
             writebuff( buff, fmp->printfc, MPS_TO_MPH(wpt->speed));
-       } else
-       if (strcmp(fmp->key, "PATH_SPEED_KNOTS") == 0) {
+           break;
+       case XT_PATH_SPEED_KNOTS:
             writebuff( buff, fmp->printfc, MPS_TO_KNOTS(wpt->speed));
-       } else
-       if (strcmp(fmp->key, "PATH_COURSE") == 0) {
+           break;
+       case XT_PATH_COURSE:
             writebuff( buff, fmp->printfc, wpt->course );
-       } else
+           break;
 
         /* HEART RATE CONVERSION***********************************************/
-        if (strcmp(fmp->key, "HEART_RATE") == 0) {
+        case XT_HEART_RATE:
             writebuff(buff, fmp->printfc, wpt->heartrate);
-        } else
+            break;
         /* CADENCE CONVERSION***********************************************/
-        if (strcmp(fmp->key, "CADENCE") == 0) {
+        case XT_CADENCE:
             writebuff(buff, fmp->printfc, wpt->cadence);
-        } else
+            break;
         /* TIME CONVERSIONS**************************************************/
-        if (strcmp(fmp->key, "EXCEL_TIME") == 0) {
+        case XT_EXCEL_TIME:
             /* creation time as an excel (double) time */
             writebuff(buff, fmp->printfc, TIMET_TO_EXCEL(wpt->creation_time));
-        } else
-        if (strcmp(fmp->key, "TIMET_TIME") == 0) {
+            break;
+        case XT_TIMET_TIME:
             /* time as a time_t variable */
             writebuff(buff, fmp->printfc, wpt->creation_time);
-        } else
-        if (strcmp(fmp->key, "YYYYMMDD_TIME") == 0) {
+            break;
+        case XT_YYYYMMDD_TIME:
            writebuff(buff, fmp->printfc, time_to_yyyymmdd(wpt->creation_time));
-       } else
-       if (strcmp(fmp->key, "GMT_TIME") == 0) {
+           break;
+       case XT_GMT_TIME:
            writetime(buff, sizeof buff, fmp->printfc, wpt->creation_time, 1 );
-       } else
-        if (strcmp(fmp->key, "LOCAL_TIME") == 0) {
+           break;
+        case XT_LOCAL_TIME:
             writetime(buff, sizeof buff, fmp->printfc, wpt->creation_time, 0 );
-       } else
-        if (strcmp(fmp->key, "HMSG_TIME") == 0) {
+           break;
+        case XT_HMSG_TIME:
             writehms(buff, sizeof buff, fmp->printfc, wpt->creation_time, 1 );
-       } else
-        if (strcmp(fmp->key, "HMSL_TIME") == 0) {
+           break;
+        case XT_HMSL_TIME:
             writehms(buff, sizeof buff, fmp->printfc, wpt->creation_time, 0 );
-       } else
-       if (strcmp(fmp->key, "ISO_TIME") == 0) {
+           break;
+       case XT_ISO_TIME:
             writetime(buff, sizeof buff, "%Y-%m-%dT%H:%M:%SZ", wpt->creation_time, 1 );
-       } else
-       if (strcmp(fmp->key, "ISO_TIME_MS") == 0) {
+           break;
+       case XT_ISO_TIME_MS:
             xml_fill_in_time(buff, wpt->creation_time, 
                wpt->microseconds, XML_LONG_TIME);
-       } else
-        if (strcmp(fmp->key, "GEOCACHE_LAST_FOUND") == 0) {
+           break;
+        case XT_GEOCACHE_LAST_FOUND:
            writebuff(buff, fmp->printfc, time_to_yyyymmdd(wpt->gc_data.last_found));
-       } else
+           break;
 
         /* GEOCACHE STUFF **************************************************/
-        if (strcmp(fmp->key, "GEOCACHE_DIFF") == 0) {
+        case XT_GEOCACHE_DIFF:
             /* Geocache Difficulty as a double */
             writebuff(buff, fmp->printfc, wpt->gc_data.diff / 10.0);
            field_is_unknown = !wpt->gc_data.diff;
-        } else
-        if (strcmp(fmp->key, "GEOCACHE_TERR") == 0) {
+            break;
+        case XT_GEOCACHE_TERR:
             /* Geocache Terrain as a double */
             writebuff(buff, fmp->printfc, wpt->gc_data.terr / 10.0);
            field_is_unknown = !wpt->gc_data.terr;
-        } else
-        if (strcmp(fmp->key, "GEOCACHE_CONTAINER") == 0) {
+            break;
+        case XT_GEOCACHE_CONTAINER:
             /* Geocache Container */
             writebuff(buff, fmp->printfc, gs_get_container(wpt->gc_data.container));
            field_is_unknown = wpt->gc_data.container == gc_unknown;
-       } else
-       if (strcmp(fmp->key, "GEOCACHE_TYPE") == 0) {
+           break;
+       case XT_GEOCACHE_TYPE:
             /* Geocache Type */
             writebuff(buff, fmp->printfc, gs_get_cachetype(wpt->gc_data.type));
            field_is_unknown = wpt->gc_data.type == gt_unknown;
-        } else 
-       if (strcmp(fmp->key, "GEOCACHE_HINT") == 0) {
+            break; 
+       case XT_GEOCACHE_HINT:
            writebuff(buff, fmp->printfc, NONULL(wpt->gc_data.hint));
            field_is_unknown = !wpt->gc_data.hint;
-        } else 
-       if (strcmp(fmp->key, "GEOCACHE_PLACER") == 0) {
+            break; 
+       case XT_GEOCACHE_PLACER:
            writebuff(buff, fmp->printfc, NONULL(wpt->gc_data.placer));
            field_is_unknown = !wpt->gc_data.placer;
-        } else
+            break;
        /* Tracks and Routes ***********************************************/
-       if (strcmp(fmp->key, "TRACK_NAME") == 0) {
+       case XT_TRACK_NAME:
            if (csv_track) writebuff(buff, fmp->printfc, NONULL(csv_track->rte_name));
-        } else
-       if (strcmp(fmp->key, "ROUTE_NAME") == 0) {
+            break;
+       case XT_ROUTE_NAME:
            if (csv_route) writebuff(buff, fmp->printfc, NONULL(csv_route->rte_name));
-        } else
+            break;
        
        /* GPS STUFF *******************************************************/
-       if (strcmp(fmp->key, "GPS_HDOP") == 0) {
+       case XT_GPS_HDOP:
             writebuff(buff, fmp->printfc, wpt->hdop);
            field_is_unknown = !wpt->hdop;
-        } else
-       if (strcmp(fmp->key, "GPS_VDOP") == 0) {
+            break;
+       case XT_GPS_VDOP:
             writebuff(buff, fmp->printfc, wpt->vdop);
            field_is_unknown = !wpt->vdop;
-        } else
-       if (strcmp(fmp->key, "GPS_PDOP") == 0) {
+            break;
+       case XT_GPS_PDOP:
             writebuff(buff, fmp->printfc, wpt->pdop);
            field_is_unknown = !wpt->pdop;
-        } else
-       if (strcmp(fmp->key, "GPS_SAT") == 0) {
+            break;
+       case XT_GPS_SAT:
             writebuff(buff, fmp->printfc, wpt->sat);
            field_is_unknown = !wpt->sat;
-        } else
-       if (strcmp(fmp->key, "GPS_FIX") == 0) {
+            break;
+       case XT_GPS_FIX: {
                char *fix = NULL;
                switch (wpt->fix) {
                        case fix_unknown:
@@ -1578,11 +1664,20 @@ xcsv_waypt_pr(const waypoint *wpt)
                                break;
                }
                writebuff(buff, fmp->printfc, fix);
-        } else {
-                       warning( MYNAME ": Unknown style directive: %s\n", fmp->key);
-        }
-       
-
+               }
+               break;
+       case -1:
+               if (strncmp(fmp->key, "LON_10E", 7) == 0) {
+                       writebuff(buff, fmp->printfc, lon * pow((double)10, atof(fmp->key+7)));
+               } else 
+               if (strncmp(fmp->key, "LAT_10E", 7) == 0) {
+                       writebuff(buff, fmp->printfc, lat * pow((double)10, atof(fmp->key+7)));
+               }
+               break;
+       default:
+               warning( MYNAME ": Unknown style directive: %s\n", fmp->key);
+               break;
+       }
         obuff = csv_stringclean(buff, xcsv_file.badchars);
 
        if (field_is_unknown && fmp->options & OPTIONS_OPTIONAL) {
@@ -1601,7 +1696,7 @@ xcsv_waypt_pr(const waypoint *wpt)
 
 next:
        xfree(obuff);
-    }
+       }
 
     gbfprintf (xcsv_file.xcsvfp, "%s", xcsv_file.record_delimiter);
 
diff --git a/xcsv_tokens.in b/xcsv_tokens.in
new file mode 100644 (file)
index 0000000..dc98a16
--- /dev/null
@@ -0,0 +1,62 @@
+struct xt_mapping {char *name; int xt_token; };
+%%
+ALT_FEET, XT_ALT_FEET
+ALT_METERS, XT_ALT_METERS
+ANYNAME, XT_ANYNAME
+CADENCE, XT_CADENCE
+CONSTANT, XT_CONSTANT
+DESCRIPTION, XT_DESCRIPTION
+EXCEL_TIME, XT_EXCEL_TIME
+GEOCACHE_CONTAINER, XT_GEOCACHE_CONTAINER
+GEOCACHE_DIFF, XT_GEOCACHE_DIFF
+GEOCACHE_HINT, XT_GEOCACHE_HINT
+GEOCACHE_LAST_FOUND, XT_GEOCACHE_LAST_FOUND
+GEOCACHE_PLACER, XT_GEOCACHE_PLACER
+GEOCACHE_TERR, XT_GEOCACHE_TERR
+GEOCACHE_TYPE, XT_GEOCACHE_TYPE
+GMT_TIME, XT_GMT_TIME
+GPS_FIX, XT_GPS_FIX
+GPS_HDOP, XT_GPS_HDOP
+GPS_PDOP, XT_GPS_PDOP
+GPS_SAT, XT_GPS_SAT
+GPS_VDOP, XT_GPS_VDOP
+HEART_RATE, XT_HEART_RATE
+HMSG_TIME, XT_HMSG_TIME
+HMSL_TIME, XT_HMSL_TIME
+ICON_DESCR, XT_ICON_DESCR
+IGNORE, XT_IGNORE
+INDEX, XT_INDEX
+ISO_TIME, XT_ISO_TIME
+ISO_TIME_MS, XT_ISO_TIME_MS
+LATLON_HUMAN_READABLE, XT_LATLON_HUMAN_READABLE
+LAT_DECIMAL, XT_LAT_DECIMAL
+LAT_DECIMALDIR, XT_LAT_DECIMALDIR
+LAT_DIR, XT_LAT_DIR
+LAT_DIRDECIMAL, XT_LAT_DIRDECIMAL
+LAT_HUMAN_READABLE, XT_LAT_HUMAN_READABLE
+LAT_INT32DEG, XT_LAT_INT32DEG
+LAT_NMEA, XT_LAT_NMEA
+LOCAL_TIME, XT_LOCAL_TIME
+LON_DECIMAL, XT_LON_DECIMAL
+LON_DECIMALDIR, XT_LON_DECIMALDIR
+LON_DIR, XT_LON_DIR
+LON_DIRDECIMAL, XT_LON_DIRDECIMAL
+LON_HUMAN_READABLE, XT_LON_HUMAN_READABLE
+LON_INT32DEG, XT_LON_INT32DEG
+LON_NMEA, XT_LON_NMEA
+MAP_EN_BNG, XT_MAP_EN_BNG
+NOTES, XT_NOTES
+PATH_COURSE, XT_PATH_COURSE
+PATH_DISTANCE_KM, XT_PATH_DISTANCE_KM
+PATH_DISTANCE_MILES, XT_PATH_DISTANCE_MILES
+PATH_SPEED, XT_PATH_SPEED
+PATH_SPEED_KNOTS, XT_PATH_SPEED_KNOTS
+PATH_SPEED_KPH, XT_PATH_SPEED_KPH
+PATH_SPEED_MPH, XT_PATH_SPEED_MPH
+ROUTE_NAME, XT_ROUTE_NAME
+SHORTNAME, XT_SHORTNAME
+TIMET_TIME, XT_TIMET_TIME
+TRACK_NAME, XT_TRACK_NAME
+URL, XT_URL
+URL_LINK_TEXT, XT_URL_LINK_TEXT
+YYYYMMDD_TIME, XT_YYYYMMDD_TIME